package com.common.template;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

import com.common.DateUtils;

import freemarker.template.Template;

/**
 * 描述：代码生成器 Created by Ay on 2017/5/1.
 */
public class CodeGenerateUtils {

	private final String AUTHOR = "ljz";
	private final String tableName = "pi_wwyt";
	private final String tableComment = "";
	private final String packageName = "pi";
	// private final String tableAnnotation = "人员表";
	private final String URL = "jdbc:mysql://192.168.20.145:3306/cmp_dev?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8";
	private final String USER = "cmp_dev";
	private final String PASSWORD = "xydc@test0987";
	private final String DRIVER = "com.mysql.cj.jdbc.Driver";
	private final String diskPath = "D:\\com";
	private final String changeTableName = lineToHump(trimPre(tableName), true);
	private final String nocapTableName = lineToHump(trimPre(tableName), false);
	private Map<String, Object> dataMap = new HashMap<String, Object>();

	public Connection getConnection() throws Exception {
		Class.forName(DRIVER);
		Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
		return connection;
	}

	public static void main(String[] args) throws Exception {
		CodeGenerateUtils codeGenerateUtils = new CodeGenerateUtils();
		codeGenerateUtils.generate();
	}

	public String lineToHump(String str, boolean isCap) {
		Pattern linePattern = Pattern.compile("_(\\w)");
		str = str.toLowerCase();
		Matcher matcher = linePattern.matcher(str);
		StringBuffer sb = new StringBuffer();
		while (matcher.find()) {
			matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
		}
		matcher.appendTail(sb);
		if (isCap) {
			return StringUtils.capitalize(sb.toString());
		} else {
			return sb.toString();
		}
	}

	public String trimPre(String string) {
		String resultString = string.substring(string.indexOf('_') + 1, string.length());
		return StringUtils.capitalize(resultString);
	}

	public void generate() throws Exception {
		Connection connection = getConnection();
		try {
			Statement st = connection.createStatement();
			ResultSet rset = st.executeQuery("SELECT * FROM " + tableName + " limit 1");
			ResultSetMetaData md = rset.getMetaData();
			DatabaseMetaData databaseMetaData = connection.getMetaData();

			this.dataMap.put("table_name_small", tableName);
			this.dataMap.put("table_name", changeTableName);
			this.dataMap.put("nocapTableName", nocapTableName);
			this.dataMap.put("author", AUTHOR);
			this.dataMap.put("packageName", packageName);
			this.dataMap.put("tableComment", tableComment);
			this.dataMap.put("date", DateUtils.getCurrentDate());
			this.dataMap.put("model_column", setColumn(md, databaseMetaData));

//			ResultSet resultSet = databaseMetaData.getColumns(null, "%", tableName, null);
			// 生成Mapper文件
			generateMapperFile();
			// 生成Dao文件
			generateDaoFile();
			// 生成服务实现层文件
			generateServiceImplFile();
			// 生成test文件
			generateTestFile();
			// 生成Controller层文件
			generateControllerFile();
			// 生成Model文件
			generateModelFile();
			// 生成jsp文件
			generateJspFile();

			rset.close();
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			connection.close();
		}
	}

	private void generateModelFile() throws Exception {
		final String suffix = "Model.java";
		String tempString = trimPre(this.tableName);
		String fileNameString = lineToHump(tempString, true);
		final String path = diskPath + "/" + fileNameString + suffix;
		System.out.println(path.toString());
		final String templateName = "model.ftl";
		File mapperFile = new File(path);
		generateFileByTemplate(templateName, mapperFile);
	}

	private void generateJspFile() throws Exception {
		final String suffix = ".jsp";
		int index = this.tableName.lastIndexOf('_');
		String tempString = this.tableName.substring(index + 1, this.tableName.length());
		String fileNameString = lineToHump(tempString, false);
		final String path = diskPath + "/" + fileNameString + suffix;
		System.out.println(path.toString());
		final String templateName = "jsp.ftl";
		File mapperFile = new File(path);
		generateFileByTemplate(templateName, mapperFile);
	}

	private void generateControllerFile() throws Exception {
		final String suffix = "Controller.java";
		String tempString = trimPre(this.tableName);
		String fileNameString = lineToHump(tempString, true);
		final String path = diskPath + "/" + fileNameString + suffix;
		System.out.println(path.toString());
		final String templateName = "controller.ftl";
		File mapperFile = new File(path);
		generateFileByTemplate(templateName, mapperFile);
	}

	private void generateServiceImplFile() throws Exception {
		final String suffix = "Service.java";
		String tempString = trimPre(this.tableName);
		String fileNameString = lineToHump(tempString, true);
		final String path = diskPath + "/" + fileNameString + suffix;
		System.out.println(path.toString());
		final String templateName = "service.ftl";
		File mapperFile = new File(path);
		generateFileByTemplate(templateName, mapperFile);
	}

	private void generateTestFile() throws Exception {
		final String suffix = "ServiceTest.java";
		String tempString = trimPre(this.tableName);
		String fileNameString = lineToHump(tempString, true);
		final String path = diskPath + "/" + fileNameString + suffix;
		System.out.println(path.toString());
		final String templateName = "test.ftl";
		File mapperFile = new File(path);
		generateFileByTemplate(templateName, mapperFile);
	}

	private List<ColumnClass> setColumn(ResultSetMetaData md, DatabaseMetaData databaseMetaData) throws SQLException {
		// 获取所有字段列表及属性
		List<ColumnClass> columnClassList = new ArrayList<ColumnClass>();
		List<String> colList = new ArrayList<String>();// 为了方便找出非主键
//		for (int i = 1; i <= md.getColumnCount(); i++) {
//			ColumnClass columnClass = new ColumnClass();
//			// 获取字段名称
//			columnClass.setColumnName(md.getColumnName(i));
//			columnClass.setColumnComment(md.getColumnLabel(i));
//			// 获取字段类型
//			// columnClass.setColumnType(resultSet.getString("TYPE_NAME"));
//			columnClass.setColumnTypeInt(md.getColumnType(i));
//			// 转换字段名称，如 sys_name 变成 SysName
//			columnClass.setChangeColumnName(replaceUnderLineAndUpperCase(columnClass.getColumnName(), false));
//			columnClass.setCapColumnName(replaceUnderLineAndUpperCase(columnClass.getColumnName(), true));
//			columnClass.setIsPri("0");
//			columnClassList.add(columnClass);// 字段在数据库的注释
//			colList.add(columnClass.getColumnName());
//		}
		ResultSet rscResultSet = databaseMetaData.getColumns(null, "%", this.tableName, "%");
		while (rscResultSet.next()) {
			ColumnClass columnClass = new ColumnClass();
			columnClass.setColumnName(rscResultSet.getString("COLUMN_NAME"));
			columnClass.setColumnComment(rscResultSet.getString("REMARKS"));
			columnClass.setColumnType(rscResultSet.getString("TYPE_NAME"));
			columnClass.setChangeColumnName(replaceUnderLineAndUpperCase(columnClass.getColumnName(), false));
			columnClass.setCapColumnName(replaceUnderLineAndUpperCase(columnClass.getColumnName(), true));
			columnClass.setIsPri("0");
			columnClassList.add(columnClass);// 字段在数据库的注释
			colList.add(columnClass.getColumnName());
//			System.out.println("字段名：" + rscResultSet.getString("COLUMN_NAME") + "\t字段注释："
//					+ rscResultSet.getString("REMARKS") + "\t字段数据类型：" + rscResultSet.getString("TYPE_NAME"));
		}
		// 获取主键及非主键列表
		ResultSet rsPri = databaseMetaData.getPrimaryKeys(null, USER.toUpperCase(), tableName);
		List<String> priList = new ArrayList();
		while (rsPri.next()) {
			String priString = rsPri.getString(4);
			priList.add(replaceUnderLineAndUpperCase(priString, false));
			for (ColumnClass columnClass : columnClassList) {
				if (columnClass.getColumnName().equals(priString)) {
					columnClass.setIsPri("1");
					break;
				}
			}
		}
		rsPri.close();
		this.dataMap.put("model_pri", priList);
		return columnClassList;
	}

	private void generateMapperFile() throws Exception {
		final String suffix = "Mapper.xml";
		String tempString = trimPre(this.tableName);
		String fileNameString = lineToHump(tempString, true);
		final String path = diskPath + "/" + fileNameString + suffix;
		System.out.println(path.toString());
		final String templateName = "mapper.ftl";
		File mapperFile = new File(path);
		generateFileByTemplate(templateName, mapperFile);
	}

	private void generateDaoFile() throws Exception {
		final String suffix = "Dao.java";
		String tempString = trimPre(this.tableName);
		String fileNameString = lineToHump(tempString, true);
		final String path = diskPath + "/" + fileNameString + suffix;
		System.out.println(path.toString());
		final String templateName = "dao.ftl";
		File mapperFile = new File(path);
		generateFileByTemplate(templateName, mapperFile);

	}

	private void generateFileByTemplate(final String templateName, File file) throws Exception {
		Template template = FreeMarkerTemplateUtils.getTemplate(templateName);
		FileOutputStream fos = new FileOutputStream(file);
//		dataMap.put("table_annotation", tableAnnotation);
		Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"), 10240);
		template.process(dataMap, out);
		out.flush();
		out.close();
	}

	public String replaceUnderLineAndUpperCase(String str, boolean isCap) {
		StringBuffer sb = new StringBuffer();
		sb.append(str);
		int count = sb.indexOf("_");
		while (count != 0) {
			int num = sb.indexOf("_", count);
			count = num + 1;
			if (num != -1) {
				char ss = sb.charAt(count);
				char ia = (char) (ss - 32);
				sb.replace(count, count + 1, ia + "");
			}
		}
		String result = sb.toString().replaceAll("_", "");
		if (isCap) {
			return StringUtils.capitalize(result);
		} else {
			return result;
		}
	}

}